package com.hotswap.utils;

import com.hotswap.dialog.MyToolWindow;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.lang.management.ManagementFactory;
import java.security.SecureRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AppUtils {

    private static String PID = "-1";

    private static final SecureRandom random = new SecureRandom();

    private static Pattern packagePattern = Pattern.compile("package\\s*(\\S*);");

    private static Pattern classPattern = Pattern.compile("public\\s*class\\s*([a-zA-Z0-9_$]*)");

    static {
        // https://stackoverflow.com/a/7690178
        String jvmName = ManagementFactory.getRuntimeMXBean().getName();
        int index = jvmName.indexOf('@');

        if (index > 0) {
            try {
                PID = Long.toString(Long.parseLong(jvmName.substring(0, index)));
            } catch (Throwable e) {
                // ignore
            }
        }
    }

    public static String getPid() {
        return PID;
    }

    public static void copyStreamToFile(InputStream in, String outPath) throws Exception {
        try (OutputStream out = new FileOutputStream(outPath, false)) {
            copy(in, out, new byte[4096]);
        } catch (Throwable e) {
            throw e;
        }
    }

    public static long copy(InputStream input, OutputStream output, byte[] buffer) throws IOException {
        long count;
        int n;
        for (count = 0L; -1 != (n = input.read(buffer)); count += (long) n) {
            output.write(buffer, 0, n);
        }

        return count;
    }

    public static String getClassName(String newCode) {
        Matcher packageMatcher = packagePattern.matcher(newCode);
        Matcher classMatcher = classPattern.matcher(newCode);
        if (!(packageMatcher.find() && classMatcher.find())) {
            throw new IllegalStateException("This is an illegal class");
        }
        String className = packageMatcher.group(1) + "." + classMatcher.group(1);
        return className;
    }

    public static String getSimpleClassName(String newCode) {
        Matcher classMatcher = classPattern.matcher(newCode);
        if (!classMatcher.find()) {
            throw new IllegalStateException("This is an illegal class");
        }
        return classMatcher.group(1);
    }

    public static String runCommand(String cmd) {
        try {
            Runtime runtime = Runtime.getRuntime();
            Process pro = runtime.exec(new String[]{"/bin/sh", "-c", cmd});
            int status = pro.waitFor();
            BufferedReader br = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            StringBuffer buffer = new StringBuffer();
            String line;
            while ((line = br.readLine()) != null) {
                buffer.append(line).append("\n");
            }
            if (status != 0) {
                throw new RuntimeException("Failed to call shell's command");
            }
            return buffer.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String delombok(String code) {
        try {
            long n = random.nextLong();
            if (n == Long.MIN_VALUE) {
                n = 0;      // corner case
            } else {
                n = Math.abs(n);
            }
            String javaFileName = getSimpleClassName(code) + ".java";
            String path = Long.toString(n) + File.separator;
            File javaFile = new File(path + File.separator + javaFileName);
            FileUtils.write(javaFile, code);

            File lombokFile = new File("lombok.jar");
            if (!lombokFile.exists()) {
                FileUtils.copyInputStreamToFile(AppUtils.class.getResourceAsStream("/lib/lombok-1.18.18.jar"), lombokFile);
            }
            String javaHome = System.getProperty("java.home");
            String cmd = "'" + javaHome + "'" + "/bin/java -jar lombok.jar delombok -p "
                    + "'" + javaFile.getAbsolutePath() + "'" + " 2>/dev/null";
            return runCommand(cmd);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}